#include "Squad.h"
#include <BWAPI.h>
#include <BWTA.h>
#include "BaseTactic.h"
#include "PotentialMap.h"
#include "MathHelper.h"
#include "TacticsManager.h"
#include <algorithm>

std::set<BWAPI::Unit*> _units;
BWAPI::UnitType _unitType;
//BaseTactic _tactic;
PotentialMap _tactic;
Squad::Squad()
{
}
Squad::Squad(std::set<BWAPI::Unit*> units,BaseTactic tactic)
{
	_units = units;
	//_tactic = tactic;
	_unitType = (*_units.begin())->getType();
}
Squad::Squad(BWAPI::Unit* unit,BaseTactic tactic)
{
	_units.insert(unit);
	//_tactic = tactic;
	_unitType = (*_units.begin())->getType();
}
void Squad::AddUnit(BWAPI::Unit* unit)
{
	_units.insert(unit);
}
void Squad::RemoveUnit(BWAPI::Unit* unit)
{
	for(std::set<BWAPI::Unit*>::const_iterator u = _units.begin(); u != _units.end(); u++)
	{
		if(unit == (*u))
		{
			_units.erase(u);
		}
	}
}


bool SortPredicate(const std::pair<BWAPI::Unit*,int>& lhs, const std::pair<BWAPI::Unit*,int>& rhs) 
{ 
	return lhs.second < rhs.second; 
} 

void Squad::ExecuteTactics()
{
	/*
		TARGETING!!

		NEEDED for intelligent targeting..

		find how many of my units is needed to kill the enemie unit. Select the enemy depending on distance.
		Select the right of my units to attack the enemie units.
	*/
	BWAPI::Position squadCenter = MathHelper::GetSquadCenterPosition(_units);
	std::list<std::pair<BWAPI::Unit*,int>> unitsAbleToAttack;
	std::list<std::pair<BWAPI::Unit*,int>> unitsNotAbleToAttack;
	for each (BWAPI::Unit* unit in BWAPI::Broodwar->enemy()->getUnits())
	{
		if(unit->exists() && unit->isVisible())
		{
			int distance = unit->getDistance(squadCenter);

			if(_unitType.isFlyer())
			{
				std::pair<BWAPI::Unit*,int> currentUnit (unit,distance);
				if(unit->getType().airWeapon() != BWAPI::WeaponTypes::None)
				{
					unitsAbleToAttack.push_back(currentUnit);
				}
				else
				{
					unitsNotAbleToAttack.push_back(currentUnit);
				}
			}
			else
			{
				//DO STUFF!!!!!!!
			}
		}
	}
	//Sorting the list by distance
	unitsAbleToAttack.sort(SortPredicate);
	

	/*
		EXECUTING
	*/
	std::set<BWAPI::Unit*>::const_iterator u = _units.begin();
	for each(std::pair<BWAPI::Unit*,int> unit in unitsAbleToAttack)
	{
		int healthLeft = unit.first->getHitPoints();
		for(; u != _units.end(); u++)
		{
			if(healthLeft < 0)
			{
				break;
			}

			if((*u)->exists())
			{
				if(unit.first->getType().isFlyer())
				{
					//DO STUFF!!!!!!!
				}
				else
				{
					healthLeft -= (*u)->getType().groundWeapon().damageAmount();
					_tactic.ExecuteTactic((*u),_units,unit.first,true);
					
				}
			}
		}
	}
}
int Squad::GetSize()
{
	int number = 0;
	for(std::set<BWAPI::Unit*>::iterator u = _units.begin(); u != _units.end(); u++)
	{
		if((*u)->exists())
		{
			number++;
		}
	}
	return number;
}
BWAPI::UnitType Squad::GetUnitType()
{
	return _unitType;
}
BWAPI::Position Squad::GetSquadCenter()
{
	int mass = 1;
	int n = 0;
	int x = 0;
	int y = 0;
	for(std::set<BWAPI::Unit*>::const_iterator i = _units.begin(); i != _units.end(); i++)
	{
		if((*i)->exists())
		{
			n++;
			BWAPI::Position unitPos = (*i)->getPosition();
			x += (mass*unitPos.x());
		}
	}
	x = x/(n*mass);

	for(std::set<BWAPI::Unit*>::const_iterator j = _units.begin(); j != _units.end(); j++)
	{
		if((*j)->exists())
		{
			BWAPI::Position unitPos = (*j)->getPosition();
			y += (mass*unitPos.y());
		}
	}
	y = y/(n*mass);

	//Center is now calculated
	
	return BWAPI::Position(x,y);

}